package com.ecr.hub.database.dao.impl;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ecr.hub.database.DaoCopyException;
import com.ecr.hub.database.dao.IDaoComposition;
import com.ecr.hub.database.dao.IDaoSillon;
import com.ecr.hub.database.mapper.MapperComposition;
import com.ecr.hub.model.composition.Composition;

@Repository("daoComposition")
public class DaoCompositionImpl extends MapperComposition implements
		IDaoComposition {

	@Resource(name = "daoSillon")
	IDaoSillon daoSillon;

	// Insertion d'une ligne de composition avec l'ensemble de ses informations.
	private static final String REQ_INSERT_COMPOSITION = "INSERT INTO hub_compo (num_lot, wagon_id, pos_num, "
			+ "pos_rail_id, pos_rail_save_id, pos_from_rail, destination_id, destination_ext_id, sillon_id, lading, "
			+ "weight_lading, comment, ate, brake_force) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

	// Suppression d'une ligne de composition à partir de son id.
	private static final String REQ_DELETE = "DELETE FROM hub_compo WHERE id=?";

	// Suppression de la totalité des compositions pour un sillon.
	private static final String REQ_DELETE_COMPO = "DELETE FROM hub_compo WHERE sillon_id=?";

	// Mise à jour d'une composition à partir de son id (ajouter les champs au
	// besoin).
	private static final String REQ_UPDATE = "UPDATE hub_compo SET pos_num=? WHERE id=?";

	// Récupération de l'identifiant interne du wagon (obligé de mettre cette
	// requête ici).
	private static final String REQ_SELECT_WAGON_ID = "SELECT id FROM hub_wagon WHERE ext_id=?";

	// Insertion wagon avec informations minimales (obligé de mettre cette
	// requête ici).
	private static final String REQ_INSERT_WAGON = "INSERT INTO hub_wagon (ext_id, type_id, "
			+ "owner, riv) VALUES (?,?,?,?)";

	// Récupération de l'id interne d'un wagon après son insertion (obligé de
	// mettre cette requête ici).
	private static final String REQ_SELECT_LAST_WAGON_ID = "SELECT LAST_INSERT_ID() FROM hub_wagon LIMIT 1";

	// Requête pour l'historisation des compositions (1/2).
	private static final String REQ_HISTO_MOVE = "INSERT INTO hub_histo_compo "
			+ " (SELECT * FROM hub_compo WHERE sillon_id=?)";

	// Requête pour l'historisation des compositions (2/2).
	private static final String REQ_HISTO_DEL = "DELETE FROM hub_compo WHERE sillon_id=?";

	@Autowired
	JdbcTemplate jdbcTemplate;

	/**
	 * Insertion de la composition d'un train à l'arrivée
	 */
	@Override
	@Transactional
	public void integrate(List<Composition> compositions)
			throws DataAccessException {

		for (Composition composition : compositions) {
			// Récupération de l'id interne du wagon.
			int wagonId;
			try {
				wagonId = jdbcTemplate.queryForInt(REQ_SELECT_WAGON_ID,
						new Object[] { composition.getWagon().getExtId() });
			} catch (EmptyResultDataAccessException e) {
				// Insertion du wagon dans la base wagon avec des informations
				// minimales.
				// TODO :placer GEFCO, etc.. en variable paramétrable.
				composition.getWagon().setOwner("GEFCO");
				composition.getWagon().setRiv("Non");
				// Type wagon inconnu.
				composition.getWagon().getType().setId(2);
				jdbcTemplate.update(REQ_INSERT_WAGON, new Object[] {
						composition.getWagon().getExtId(),
						composition.getWagon().getType().getId(),
						composition.getWagon().getOwner(),
						composition.getWagon().getRiv() });

				wagonId = jdbcTemplate.queryForInt(REQ_SELECT_LAST_WAGON_ID);
			}

			// Mise à jour de la composition avec l'identifiant du wagon.
			composition.getWagon().setId(wagonId);
			// Insertion de la composition.
			jdbcTemplate.update(
					REQ_INSERT_COMPOSITION,
					new Object[] {
							composition.getWagon().getNumLot(),
							composition.getWagon().getId(),
							composition.getWagon().getCurrentPos().getPosNum(),
							composition.getWagon().getCurrentPos()
									.getPosRailId(),
							composition.getPosRailSaveId(),
							composition.getWagon().getFromRail(),
							composition.getWagon().getDestinationId(),
							composition.getDestinationExtId(),
							composition.getSillonId(),
							composition.getWagon().getLading(),
							composition.getWagon().getWeightLading(),
							composition.getWagon().getComment(),
							composition.getWagon().getAte(),
							composition.getWagon().getBrakeForce() });
		}
	}

	/**
	 * Insertion d'une composition d'un train au départ.
	 */
	@Override
	@Transactional
	public void insert(List<Composition> compositions)
			throws DataAccessException {

		for (Composition composition : compositions) {
			jdbcTemplate.update(
					REQ_INSERT_COMPOSITION,
					new Object[] {
							composition.getWagon().getNumLot(),
							composition.getWagon().getId(),
							composition.getWagon().getCurrentPos().getPosNum(),
							composition.getWagon().getCurrentPos()
									.getPosRailId(),
							composition.getPosRailSaveId(),
							composition.getWagon().getFromRail(),
							composition.getWagon().getDestinationId(),
							composition.getDestinationExtId(),
							composition.getSillonId(),
							composition.getWagon().getLading(),
							composition.getWagon().getWeightLading(),
							composition.getWagon().getComment(),
							composition.getWagon().getAte(),
							composition.getWagon().getBrakeForce() });
		}
	}

	/**
	 * Suppression d'une ligne de composition (seulement une ligne).
	 */
	@Override
	public void delete(Composition composition) throws DataAccessException {

		jdbcTemplate.update(REQ_DELETE, new Object[] { composition.getId() });
	}

	/**
	 * Suppression de toutes les lignes de composition pour un sillon.
	 */
	@Override
	public void deleteAll(int sillonId) throws DataAccessException {

		jdbcTemplate.update(REQ_DELETE_COMPO, new Object[] { sillonId });
	}

	/**
	 * Mise à jour d'une composition (On voit au cas par cas pour ajouter les
	 * champs dont on a besoin dans la mise à jour.)
	 */
	@Override
	public void update(Composition composition) throws DataAccessException {

		jdbcTemplate.update(REQ_UPDATE,
				new Object[] {
						composition.getWagon().getCurrentPos().getPosNum(),
						composition.getId() });
	}

	/**
	 * Historisation de l'ensemble des lignes pour une composition. On transfert
	 * l'ensemble des lignes liées à un sillon pour une composition. En cas
	 * d'echec du transfert, on lève une exception.
	 */
	@Override
	@Transactional
	public void historize(int sillonId) throws DataAccessException {

		int nbUpdate = jdbcTemplate.update(REQ_HISTO_MOVE,
				new Object[] { sillonId });

		int nbDelete = jdbcTemplate.update(REQ_HISTO_DEL,
				new Object[] { sillonId });

		if (nbUpdate != nbDelete)
			throw new DaoCopyException(
					"Hub : Impossible de transférer les lignes compo dans la table d'historique.");
	}
}